package file

import (
	"fmt"
	"github.com/emicklei/go-restful"
	"io/ioutil"
	"kubeInstall/conf"
	"kubeInstall/pkg/logger"
	"kubeInstall/server/handlers"
	modelFile "kubeInstall/server/models/file"

	serviceFile "kubeInstall/server/services/file"

	utilsFile "kubeInstall/utils/file"
	"mime/multipart"
	"net/http"
	"strconv"
)

type fileHandler struct {
	handlers.BaseHandler
}

func NewFileHandler() handlers.IBaseHandler {
	return new(fileHandler)
}

func (f *fileHandler) AddToRoute(ws *restful.WebService) {
	ws.Route(ws.POST("/file").To(f.uploadPkg))
	ws.Route(ws.GET("/file").To(f.pkgList))
	//ws.Route(ws.PUT("/file/{package_id}/install").To(f.installSysPackage))
	/*ws.Route(ws.GET("/syspkgs").To(h.GetSysPkg))
	ws.Route(ws.GET("/images").To(h.GetImages))*/
}

func (f *fileHandler) uploadPkg(r *restful.Request, w *restful.Response) {
	//upload to jump server ,not target server.
	maxUploadSize := conf.AppSetting.MaxUploadSize
	if err := r.Request.ParseMultipartForm(maxUploadSize); err != nil {
		f.RenderError(w, fmt.Sprintf("Could not parse multipart form: %v", err), http.StatusBadRequest)
		return
	}

	// 获取文件
	fileData, fileHeader, err := r.Request.FormFile("uploadFile")
	if err != nil {
		f.RenderError(w, fmt.Sprintf("Read Form from http failed! error is : %v", err), http.StatusBadRequest)
		return
	}
	defer fileData.Close()

	fileSize := fileHeader.Size
	// 检查上传文件大小
	if fileSize > maxUploadSize {
		f.RenderError(w, fmt.Sprintf("File size over max file limit. size is %d ,limit is %d", fileSize, maxUploadSize), http.StatusBadRequest)
		return
	}

	// 检查上传文件类型
	// rpm包，deb包，tar.gz包
	fileType := fileHeader.Header.Get("Content-Type")
	//detectedFileType := http.DetectContentType
	switch fileType {
	case "application/x-tar":
		HandleDockerImages(fileHeader, fileData, w)
	// rpm pkg,binary file
	case "application/x-redhat-package-manager", "application/octet-stream":
		f.saveSysPackage(fileHeader, fileData, w)
	default:
		f.RenderError(w, fmt.Sprintf("unsupported file type %s .only support .tar or .rpm file", fileType), http.StatusBadRequest)
		return
	}

}

func (f *fileHandler) saveSysPackage(fileHeader *multipart.FileHeader, file multipart.File, resp *restful.Response) {
	// 判断目录是否存在不存在则创建目录
	if !utilsFile.Exists(conf.AppSetting.SysPackPath) {
		utilsFile.MkDir(conf.AppSetting.SysPackPath)
	}

	filePath := utilsFile.CombineFile(conf.AppSetting.SysPackPath, fileHeader.Filename)
	if utilsFile.Exists(filePath) {
		f.RenderError(resp, fmt.Sprintf("file already exist"), http.StatusBadRequest)
		return
	}
	//写入文件到磁盘
	fileBytes, _ := ioutil.ReadAll(file)

	if err := utilsFile.WriteFile(filePath, fileBytes); err != nil {
		f.RenderError(resp, fmt.Sprintf("Write to disk failed, error is : %v", err), http.StatusInternalServerError)
		return
	}

	logger.Info("read file form http stream success!")
	//记录文件信息到数据库,安装之后记录文件详细信息。
	pkg := modelFile.SysPackage{
		Name:     fileHeader.Filename,
		Size:     fileHeader.Size / 2014,
		SavePath: filePath,
	}

	data, err := serviceFile.CreateFile(pkg)

	if err != nil {
		utilsFile.RemoveFile(filePath)
		f.RenderError(resp, fmt.Sprintf("record file info failed %v", err), http.StatusInternalServerError)
		return
	}
	// http返回
	f.RenderResp(resp, data, http.StatusOK)

}


func HandleDockerImages(fileHeader *multipart.FileHeader, file multipart.File, resp *restful.Response) {

	/*//检查文件是否存在
	//todo 检查文件内容。例如manifest 文件信息。
	filePath := filepath.Join(conf.AppSetting.DockerImagesPath, fileHeader.Filename)
	if utils.Exists(filePath) {
		handlers.RenderError(resp, fmt.Sprintf("file already exist"), http.StatusBadRequest)
		return
	}
	//写入文件到磁盘
	fileBytes, _ := ioutil.ReadAll(file)
	if err := utils.WriteFile(filePath, fileBytes); err != nil {
		handlers.RenderError(resp, fmt.Sprintf("Write to disk failed, error is : %v\n", err), http.StatusInternalServerError)
		return
	}

	//记录文件信息到数据库
	var img models.DockerImage
	img.Name = fileHeader.Filename
	img.Size = fileHeader.Size / 1024

	data, err := img.Create()

	if err != nil {
		utils.RemoveFile(filePath)
		handlers.RenderError(resp, fmt.Sprintf("record docker images info failed %v\n", err), http.StatusInternalServerError)
		return
	}
	// http返回
	resp.WriteHeaderAndJson(http.StatusOK, data, restful.MIME_JSON)*/
}

func (f fileHandler) pkgList(r *restful.Request, resp *restful.Response) {

	offset, _ := strconv.Atoi(r.QueryParameter("offset"))
	limit, _ := strconv.Atoi(r.QueryParameter("limit"))

	data, err := serviceFile.GetPackageList(limit, offset)

	if err != nil {
		f.RenderError(resp, fmt.Sprintf("get sys packages failed! error is:  %v", err), http.StatusBadRequest)
		return
	}

	f.RenderResp(resp, data, http.StatusOK)

}

func (f *fileHandler) getPkg(r *restful.Request, resp *restful.Response) {

	packageId := r.PathParameter("package_id")

	data, err := serviceFile.Get(packageId)

	if err != nil {
		f.RenderError(resp, fmt.Sprintf("get package failed! error is: %v", err), http.StatusNotFound)
		return
	}

	f.RenderResp(resp, data, http.StatusOK)

}
